﻿#include <iostream>
#include <winsock.h>
#include <fstream>
#include<time.h>
#include <string>
#include "reliableUdp.h"
#pragma comment(lib, "Ws2_32.lib")

using namespace std;

char buffer[200000000];

SOCKET server;
SOCKADDR_IN serverAddr, clientAddr;

int expectedSeqNum = 0;
bool normalACK = true;

bool shakeHand() {
	while (true) {
		char recv[2];
		int clientAddrLen = sizeof(clientAddr);
		while (recvfrom(server, recv, 2, 0, (sockaddr*)&clientAddr, &clientAddrLen) == SOCKET_ERROR);
		if (checksum(recv, 2) != 0 || recv[1] != SHAKE_1) {
			continue;
		}
		cout << "Received Shake 1.\n";
		while (true) {
			recv[1] = SHAKE_2;
			recv[0] = checksum(recv + 1, 1);
			sendto(server, recv, 2, 0, (sockaddr*)&clientAddr, sizeof(clientAddr));
			cout << "Sent Shake 2.\n";
			int begin = clock();
			bool lost = false;
			while (true) {
				if (recvfrom(server, recv, 2, 0, (sockaddr*)&clientAddr, &clientAddrLen) > 0) {
					break;
				}
				if (clock() - begin > MAX_WAIT_TIME) {
					lost = true;
					cout << "Time limit for receiving Shake 3 exceeded.\n";
					break;
				}
			}
			if (lost) {
				continue;
			}
			if (checksum(recv, 2) == 0 && recv[1] == SHAKE_1) {
				continue;
			}
			else {
				if (checksum(recv, 2) == 0 && recv[1] == SHAKE_3) {
					cout << "Received Shake 3.\n";
					break;
				}
				else {
					cout << "Failed to shake hand.\n";
					return false;
				}
			}
		}
		break;
	}
	cout << "Shaking hand completed.\n";
	return true;
}

void waveHand() {
	while (true) {
		char recv[2];
		int clientAddrLen = sizeof(clientAddr);
		while (recvfrom(server, recv, 2, 0, (sockaddr*)&clientAddr, &clientAddrLen) == SOCKET_ERROR);
		if (checksum(recv, 2) != 0 || recv[1] != (char)WAVE_1) {
			continue;
		}
		cout << "Received Wave 1.\n";
		char send[2];
		send[1] = WAVE_2;
		send[0] = checksum(send + 1, 1);
		sendto(server, send, 2, 0, (sockaddr*)&clientAddr, sizeof(clientAddr));
		cout << "Sent Wave 2.\n";
		break;
	}
	Sleep(100);//假装还要发送点数据
	while (true) {
		char send[2];
		send[1] = WAVE_3;
		send[0] = checksum(send + 1, 1);
		sendto(server, send, 2, 0, (sockaddr*)&clientAddr, sizeof(clientAddr));
		cout << "Sent Wave 3.\n";
		int begin = clock();
		char recv[2];
		int clientAddrLen = sizeof(clientAddr);
		bool lost = false;
		while (recvfrom(server, recv, 2, 0, (sockaddr*)&clientAddr, &clientAddrLen) == SOCKET_ERROR) {
			if (clock() - begin > MAX_WAIT_TIME) {
				lost = true;
				cout << "Time limit for receiving Wave 4 exceeded.\n";
				break;
			}
		}
		if (!lost && checksum(recv, 2) == 0 && recv[1] == WAVE_1) {
			cout << "Received Wave 1.\n";
			send[1] = WAVE_2;
			send[0] = checksum(send + 1, 1);
			sendto(server, send, 2, 0, (sockaddr*)&clientAddr, sizeof(clientAddr));
			cout << "Sent Wave 2.\n";
			Sleep(100);
			continue;
		}
		else {
			if (!lost && checksum(recv, 2) == 0 && recv[1] == WAVE_4) {
				cout << "Received Wave 4.\n";
				break;
			}
			else {
				if (!lost && checksum(recv, 2) == 0) {
					cout << "Failed to wave hand.\n";
				}
			}
		}
	}
	cout << "Waving hand completed.\n";
}

bool gbnReceiver(char* pkt, int& fileLen) {
	int recvNum = 0;
	char recv[MAX_LEN + 5];
	int clientAddrLen = sizeof(clientAddr);
	fileLen = 0;
	char send[2];
	send[1] = -1;
	while (true) {
		while (true) {
			memset(recv, 0, sizeof(recv));
			int recvRtn = recvfrom(server, recv, MAX_LEN + 5, 0, (sockaddr*)&clientAddr, &clientAddrLen);
			if (recvRtn > 0) {
				cout << "checksum = 0: \n";
				cout << "Received packet " << recvNum++ << ", seqNum = " << (int)((unsigned char)recv[2]) << ", expectedSeqNum = " << expectedSeqNum << endl;
				if (checksum(recv, MAX_LEN + 5) == 0) {
					if ((int)((unsigned char)recv[2]) == expectedSeqNum % 256) {
						if (expectedSeqNum % 5 == 0 || recv[1] == LAST) {
							send[1] = expectedSeqNum % 256;
							send[0] = checksum(send + 1, 1);
							sendto(server, send, 2, 0, (sockaddr*)&clientAddr, sizeof(clientAddr));
							cout << "Sent ACK, ackNum = " << (int)((unsigned char)send[1]) << endl;
						}
						normalACK = true;
						expectedSeqNum++;
						break;
					}
					else {
						if (send[1] == -1) { //第一个包就丢失了，没有“old ACK”
							cout << "NO ACK!\n";
							break;
						}
						cout << "[Error] Received disordered PKT, send old ACK, ackNum = " << (int)((unsigned char)send[1]) << endl;
						sendto(server, send, 2, 0, (sockaddr*)&clientAddr, sizeof(clientAddr));
						normalACK = false;
						break;
					}
				}
				else {
					send[1] = NAK;
					send[0] = checksum(send + 1, 1);
					sendto(server, send, 2, 0, (sockaddr*)&clientAddr, sizeof(clientAddr));
					cout << "Sent NAK.\n";
				}
			}
		}
		if (!normalACK) {
			continue;
		}
		if (recv[1] == LAST) {
			int lenh = (int)((unsigned char)recv[3]);
			int lenl = (int)((unsigned char)recv[4]);
			int len = (lenh << 8) + lenl;
			for (int i = 5; i < len + 5; i++) {
				pkt[fileLen++] = recv[i];
			}
			break;
		}
		else {
			for (int i = 3; i < MAX_LEN + 3; i++) {
				pkt[fileLen++] = recv[i];
			}
		}
	}
	cout << "Received successfully.\n";
	expectedSeqNum = 0;
	return true;
}
int main() {
	WSADATA wsadata;
	if (WSAStartup(MAKEWORD(2, 2), &wsadata)) {
		printf("error");
		return 0;
	}
	//初始化
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(serverPort);
	serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	server = socket(AF_INET, SOCK_DGRAM, 0);

	/*
	unsigned long ul = 1;
	if (ioctlsocket(server, FIONBIO, (unsigned long*)&ul) == SOCKET_ERROR) {
		cout << "Set failed.\n";
	}
	*/
	int time_out = 2000;//超时
	setsockopt(server, SOL_SOCKET, SO_RCVTIMEO, (char*)&time_out, sizeof(time_out));

	if (server == INVALID_SOCKET) {
		printf("socket of server invalid!");
		closesocket(server);
		return 0;
	}
	if (bind(server, (sockaddr*)(&serverAddr), sizeof(serverAddr)) == SOCKET_ERROR) {
		printf("bind fail");
		closesocket(server);
		WSACleanup();
		return 0;
	}
	cout << "Trying to establish connection...\n";
	//开始握手
	if (!shakeHand()) {
		return 0;
	}
	cout << "Connection with client " << inet_ntoa(clientAddr.sin_addr) << ": " << ntohs(clientAddr.sin_port) << " established.\n===================================\n";
	while (true) {
		int beg = clock();
		// 接受文件名
		int len = 0;
		gbnReceiver(buffer, len);
		buffer[len] = 0;
		string fileName(buffer);
		if (!strcmp("/exit", fileName.c_str())) {
			cout << "Handling client exit request.\n";
			break;
		}
		cout << fileName << endl;
		// 清空缓冲区
		memset(buffer, 0, fileName.length());
		// 接受文件内容
		gbnReceiver(buffer, len);
		int end = clock();
		buffer[len] = 0;
		string saveDir = "C:\\Users\\16116\\Desktop\\rt\\save\\";
		string savePath = saveDir + fileName;
		ofstream out(savePath.c_str(), ofstream::binary);
		for (int i = 0; i < len; i++) {
			out << buffer[i];
		}
		out.close();
		cout << "File length: " << len << endl;
		cout << "File name: " << fileName << endl;
		double time = (double)(end - beg) / 1000;
		double speed = (double)len / time;
		cout << "Time cost: " << time << " s" << endl;
		cout << "Transfer Speed: " << speed << " B/s" << endl;
	}
	//挥手
	waveHand();
	closesocket(server);
	cout << "Connection Aborted.\n";
	WSACleanup();
	cout << "WSA cleaning up finished.\n";
	return 0;
}